#include "string_stack.h"

#include <algorithm> // std::min
#include <utility> // std::move

namespace simple::file::string_stack
{

std::string::size_type top(const std::string& stack, const std::string& delimiters)
{
	auto end = stack.find_last_not_of(delimiters);
	auto top = stack.find_last_of(delimiters, end);

	// this edge case turns out to be handled rather nicely by the usual case, but leaving the code commented here to indicate the intent
	// if(std::string::npos == top)
	// 	top = 0;
	// else
	++top;

	return top;
}

std::string pop(std::string& stack, const std::string& delimiters)
{
	auto _top = top(stack, delimiters);
	auto name = stack.substr(_top);
	stack.resize(_top);
	return name;
}

void drop(std::string& stack, const std::string& delimiters)
{
	stack.resize(top(stack, delimiters));
}

void push(std::string& stack, const std::string& content, const std::string& delimiters)
{
	if(!stack.empty() && delimiters.find(stack.back()) == std::string::npos)
		stack += delimiters.front();
	stack += content;
}

unsigned manipulator::dec(unsigned amount)
{
	return size -= std::min(size, amount);
}

manipulator::manipulator(std::string& on, std::string delimiters)
	: stack(&on), delimiters(delimiters)
{}

manipulator::manipulator(manipulator&& other) : manipulator(other)
{
	other.release();
}

manipulator& manipulator::operator=(manipulator&& other)
{
	manipulator tmp(*this); // call destructor plz am too lazy
	*this = other;
	other.release();
	return *this;
}

manipulator::~manipulator()
{
	while(size)
		drop();
}

void manipulator::release()
{
	size = 0;
}

std::string manipulator::pop()
{
	dec();
	return string_stack::pop(*stack, delimiters);
};

void manipulator::drop()
{
	string_stack::drop(*stack, delimiters);
	dec();
};

manipulator& manipulator::push(const std::string& value) &
{
	if(!value.empty())
	{
		string_stack::push(*stack, value, delimiters);
		++size;
	}
	return *this;
}

manipulator&& manipulator::push(const std::string& value) &&
{
	push(value);
	return std::move(*this);
}

} // namespace simple::file::string_stack
